package com.deer.wms.ware.task.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.deer.wms.intercept.common.data.CurrentUser;
import com.deer.wms.inventory.constant.InventoryConstant;
import com.deer.wms.inventory.model.Inventory.Inventory;
import com.deer.wms.inventory.model.Inventory.InventoryTransact;
import com.deer.wms.inventory.service.InventoryService;
import com.deer.wms.inventory.service.InventoryTransactService;
import com.deer.wms.project.root.core.result.CommonCode;
import com.deer.wms.project.root.exception.ServiceException;
import com.deer.wms.project.root.service.SuperServiceImpl;
import com.deer.wms.project.root.util.DateUtils;
import com.deer.wms.system.manage.model.user.UserInfo;
import com.deer.wms.ware.task.constant.WareTaskConstant;
import com.deer.wms.ware.task.dao.WaveDetailMapper;
import com.deer.wms.ware.task.model.SO.SoDetail;
import com.deer.wms.ware.task.model.Wave.WaveDetail;
import com.deer.wms.ware.task.model.Wave.WaveDetailCriteria;
import com.deer.wms.ware.task.model.Wave.WaveDetailDto;
import com.deer.wms.ware.task.model.pickTask.PickTask;
import com.deer.wms.ware.task.service.PickTaskService;
import com.deer.wms.ware.task.service.SoDetailService;
import com.deer.wms.ware.task.service.WaveDetailService;
import com.deer.wms.ware.task.service.WaveMasterService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * @author wei
 * @date 2020/02/02
 */
@Service
@Transactional
public class WaveDetailServiceImpl extends SuperServiceImpl<WaveDetailMapper, WaveDetail> implements WaveDetailService {

    @Autowired
    private WaveDetailMapper waveDetailMapper;
    @Autowired
    private WaveDetailService waveDetailService;
    @Autowired
    private SoMasterServiceImpl soMasterService;
    @Autowired
    private PickTaskService pickTaskService;
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private SoDetailService soDetailService;
    @Autowired
    private InventoryTransactService inventoryTransactService;

    @Override
    public List<WaveDetailDto> findList(WaveDetailCriteria criteria) {
        return waveDetailMapper.findList(criteria);
    }

    @Override
    public List<WaveDetail> getByMasterId(  Integer waveId) {
        return waveDetailMapper.getByMasterId(waveId);
    }

    @Override
    public void deleteByWaveMasterId(Integer id) {

        WaveDetailCriteria criteria = new WaveDetailCriteria();
        criteria.setWaveId(id);
        waveDetailMapper.deleteByWaveMasterCode(criteria);
    }

    @Override
    public void suggestForPick(List<WaveDetail> detailList, UserInfo wareUser, CurrentUser currentUser) {
        //波次明细 关联 仓库员
        List<WaveDetail> list = new ArrayList<>();
        for (WaveDetail waveDetail : detailList) {
            //波次明细绑定仓管员。  后续拣货是按仓管员分组进行操作
            //不能更换仓管员
            if (ObjectUtil.equals(WareTaskConstant.WAVE_STATE_PICKING, waveDetail.getState()) && ObjectUtil.notEqual(wareUser.getUserId(),
                    waveDetail.getPickUserId())) {
                throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "部分推荐的波次明细不允许更换仓管员");
            }
            if (ObjectUtil.equals(WareTaskConstant.WAVE_STATE_PROCESSING, waveDetail.getState())
                    || ObjectUtil.equals(WareTaskConstant.WAVE_STATE_PICKING, waveDetail.getState())) {
                //只需要推荐未拣货完成的
                waveDetail.setPickUserId(wareUser.getUserId());
                waveDetail.setPickUserName(wareUser.getUserName());
                list.add(waveDetail);
            }
        }

        //分配库存，调用公共方法。
        pickTaskService.createPickTask(detailList, currentUser);
    }

    @Override
    public void sendOut(List<Integer> pickIds, CurrentUser currentUser) {
        List<PickTask> pickTasks = pickTaskService.listByIds(pickIds);
        //找到对应的库存
        List<Integer> invIdList = pickTasks.stream().map(PickTask::getInventoryId).collect(Collectors.toList());
        List<Inventory> inventories = inventoryService.listByIds(invIdList);

        //先按波次明细分组  ArrayDeque
        Map<String, List<Inventory>> map = inventories.stream().collect(Collectors.groupingBy(Inventory::getBillNo));
        Set<String> waveDetailCodes = map.keySet();
        for (String waveDetailCode : waveDetailCodes) {
            WaveDetail waveDetail = waveDetailService.getOneByField("wave_detail_code", waveDetailCode);
            QueryWrapper<SoDetail> soDetailQw = new QueryWrapper<>();
            soDetailQw.eq("wave_detail_id", waveDetail.getWaveDetailId());
            //soDetailQw.ne("state", WareTaskConstant.SO_DETAIL_STATE_ALL_PICK); 目前做不到狀態管理
            List<SoDetail> soDetails = soDetailService.list(soDetailQw);

            ArrayDeque<SoDetail> ad = new ArrayDeque<>(soDetails);
            List<Inventory> allotInvs = map.get(waveDetailCode);

            //分配库存
            //多个库存对应一个波次明细   一个波次明细对应多个出库任务明细
            //  A1, A2, A3   ===>   B1
            //  B1  ===>  C1,C2,C3,C4,C5
            extracted(ad, allotInvs);
        }

        //Step2.处理库存，生成库存事务
        for (Inventory inventory : inventories) {
            this.toStockRequest(inventory, currentUser);
            inventoryService.removeById(inventory);
        }


//        soMaster.setState(WareTaskConstant.SO_STATE_OUTED);
//        soMaster.setOutTime(DateUtils.getNowDateTimeString());
//        soMaster.setOutUserId(currentUser.getUserId());
//        soMaster.setOutUserName(currentUser.getUserName());
//        soMaster.setWeight(weight);
//        soMasterService.updateById(soMaster);
        //Step3.回写单据状态
        for (PickTask pickTask : pickTasks) {
            pickTask.setSeededQuantity(pickTask.getPickQuantity());
            pickTask.setState(WareTaskConstant.PICK_STATE_OUTED);
        }
//        if (true) {throw new ServiceException(CommonCode.SERVER_INERNAL_ERROR, "test");}
        pickTaskService.updateBatchById(pickTasks);
    }

    /**
     * 分配数量，更新
     * @param queue SO 队列
     * @param allotInvs 待分配的库存
     */
    private void extracted(ArrayDeque<SoDetail> queue, List<Inventory> allotInvs) {
        Set<SoDetail> set = new HashSet<>(queue.size());
        for (Inventory allotInv : allotInvs) {
            Double quantity = allotInv.getQuantity();

            while (!queue.isEmpty()) {
                //取出队列的第一个元素
                SoDetail soDetail = queue.getFirst();
                //SO待填补的数量
                double remainQty = soDetail.getOrderQuantity() - soDetail.getDeliveryQuantity();
                if (remainQty == 0) {
                    queue.poll();
                    continue;
                }
                if (quantity < remainQty) {
                    //库存不够分配，分配后直接跳出循环
                    soDetail.setDeliveryQuantity(soDetail.getDeliveryQuantity() + quantity);
                    soDetail.setState(WareTaskConstant.SO_DETAIL_STATE_PART_SEND);
                    set.add(soDetail);
                    break;
                } else {
                    //库存足够分配，全部填满SO的数量
                    soDetail.setDeliveryQuantity(soDetail.getOrderQuantity());
                    soDetail.setState(WareTaskConstant.SO_DETAIL_STATE_ALL_SEND);
                    set.add(soDetail);

                    //扣减已分配的库存数量
                    quantity -= remainQty;
                    //队列第一个元素被分配完毕，出队列
                    queue.poll();
                }
            }
        }
        soDetailService.updateBatchById(set);
    }


    /**
     * 生成库存事务
     * @param inventory 库存
     * @param currentUser 当前用户
     * @return 库存事务
     */
    private InventoryTransact toStockRequest(Inventory inventory, CurrentUser currentUser) {
        InventoryTransact inventoryTransact = new InventoryTransact();
        //Step1.准备数据
        //仓库
        inventoryTransact.setWareId(inventory.getWareId());
        inventoryTransact.setWareName(inventory.getWareName());
        //货主
        inventoryTransact.setToOrganizationId(inventory.getOrganizationId());
        inventoryTransact.setToOrganizationName(inventory.getOrganizationName());
        //库位
        inventoryTransact.setFromCellCode(inventory.getCellCode());
        //容器
        inventoryTransact.setFromBoxCode(inventory.getBoxCode());
        //物料
        inventoryTransact.setItemCode(inventory.getItemCode());
        inventoryTransact.setItemName(inventory.getItemName());
        inventoryTransact.setImgUrl(inventory.getImgUrl());
        //批次
        inventoryTransact.setFromBatchId(inventory.getBatchId());
        inventoryTransact.setFromBatchName(inventory.getBatchName());
        //数量
        inventoryTransact.setFromQuantity(inventory.getQuantity());
        //包装 转换率
        inventoryTransact.setFromPackDetailId(inventory.getPackDetailId());
        inventoryTransact.setFromPackDescribe(inventory.getPackDescribe());
        //创建人 时间
        inventoryTransact.setCreateUserId(currentUser.getUserId());
        inventoryTransact.setCreateUserName(currentUser.getUserName());
        inventoryTransact.setCreateTime(DateUtil.now());
        //事务类型
        inventoryTransact.setTransactType(InventoryConstant.INVENTORY_TYPE_OUT);
        //来源单据号
//        inventoryTransact.setBillNo(pickTask.getPickTaskCode());

        //Step2.保存，返回
        inventoryTransactService.save(inventoryTransact);
        return inventoryTransact;
    }
}
